package framework.controller;

import java.util.*;
import java.util.regex.*;
import java.net.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.util.concurrent.*;

import framework.utils.*;
import framework.utils.dto.ActionCommand;
import framework.model.*;

/**
 * This class makes interaction with the GameServer
 * @class ServerController
 * @author Michel Jansma
 * @version 0.0.3
 */
public class ServerController extends Controller {

	public  static final Socket 	  	  SOCKET = new Socket();
	public  static final ExecutorService  EXECUTOR = Executors.newCachedThreadPool();
	public  static BufferedReader 	  	  INPUT_READER;
	public  static PrintWriter 		  	  OUTPUT_WRITER;
	public  static LinkedList<String> 	  STACK;
	
	public static ActionListener CURRENT_LISTENER;
	public static LinkedList<ActionCommand> _STACK = new LinkedList<ActionCommand>();
	
	/**********************
	 *** GLOBAL METHODS ***
	 *********************/
	
	/**
	 * Initialize ServerController
	 * @method ServerController (Constructor)
	 * @param <LoginModel> model
	 */
	public ServerController(Model model) {
		super(model);
	};
	
	/**
	 * Constructor without parameters
	 * @method ServerController (Constructor)
	 */
	public ServerController() {
		//TODO fill
	};

	/**
	 * Send command to GameServer
	 * @method sendCommand
	 * @param <String> line
	 */
	public void sendCommand(String command) {
		try {
			System.out.println(this.getClass().getName() + " -> sendCommand('" + command + "');");
			ServerController.OUTPUT_WRITER.println(command);
		} catch(Exception e) {
			System.out.println(this.getClass().getName() + " -> sendCommand() -> " + e.getMessage());
		};
	};
	
	/**
	 * @method initialize
	 * Initialize controller
	 */
	protected void initialize() {
		this.setStack();
		this.setInputReader();
		this.setOutputWriter();
	};
	
	/**********************
	 *** SETTER METHODS ***
	 *********************/
	
	protected void setCurrentListener(ActionListener listener) {
		ServerController.CURRENT_LISTENER = listener;
	};
	
	/**
	 * Initialize model
	 * @method setModel
	 * @param <LoginModel> model
	 */
	protected void setModel(Model model) {
		super.setModel(model);
	};
	
	/**
	 * Setup Socket (Make connection width GameServer)
	 * @method setSocket
	 * @param <String> serverHost,
	 * @param <Integer> serverPort
	 * @return <Boolean> isConnected
	 */
	protected boolean setSocket(String serverHost, int serverPort) {
		boolean isConnected = false;
		try {
			ServerController.SOCKET.connect(new InetSocketAddress(serverHost, serverPort));
			isConnected = ServerController.SOCKET.isConnected();
			if(isConnected) {
				//Store serverHost
				UserPreferences.setProperty("server_host", serverHost); 
				//Store serverPort
				UserPreferences.setProperty("server_port", serverPort); 
			}
			return isConnected;
		} catch(Exception e) {
			System.out.println(this.getClass().getName() + " -> setChannel() -> " + e.getMessage());
			return isConnected;
		}
	};
	
	/**
	 * @method setInputReader
	 * Setup reader for reading incoming GameServer data
	 */
	private void setInputReader() {
		try {
			ServerController.INPUT_READER  = new BufferedReader(new InputStreamReader(ServerController.SOCKET.getInputStream()));
		} catch(Exception e) {
			System.out.println(this.getClass().getName() + " -> setInputReader() -> " + e.getMessage());
		};
	};
	
	/**
	 * @method setOutputWriter
	 * Setup writer for writing data to GameServer
	 */
	private void setOutputWriter() {
		try {
			ServerController.OUTPUT_WRITER = new PrintWriter(ServerController.SOCKET.getOutputStream(), true);
		} catch(Exception e) {
			System.out.println(this.getClass().getName() + " -> setOutputWriter() -> " + e.getMessage());
		};
	};
	
	/**
	 * @method setStack
	 * Setup stack for holding requests
	 */
	private void setStack() {
		//LinkedHashSet for non-duplicated data
		ServerController.STACK = new LinkedList<String>();
	};
	
	/**
	 * @method setStackValue
	 * @param <String> value
	 * @return <Boolean> isAdded
	 */
	protected boolean setStackValue(String value) {
		if(!ServerController.STACK.contains(value)) {
			return ServerController.STACK.add(value);
		}
		return false;
	};
	
	/**
	 * Add thread to thread pool
	 * @method setThread
	 * @param <Runnable> thread
	 */
	public void setThread(Runnable thread) {
		ServerController.EXECUTOR.execute(thread);
	};
	
	/**********************
	 *** GETTER METHODS ***
	 *********************/
	
	/**
	 * @method getSocket
	 * @return <Socket> socket
	 */ 
	public Socket getSocket() {
		return ServerController.SOCKET;
	};
	
	/**
	 * @method getModel
	 * @return <LoginModel> model
	 */ 
	protected Model getModel() {
		return super.getModel();
	};

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
	};
	
}
